package me.illtamer.rpc.transport.socket.util;

import lombok.extern.slf4j.Slf4j;
import me.illtamer.rpc.entity.RpcRequest;
import me.illtamer.rpc.entity.RpcResponse;
import me.illtamer.rpc.enumeration.PackageType;
import me.illtamer.rpc.enumeration.RpcError;
import me.illtamer.rpc.exception.RpcException;
import me.illtamer.serializer.CommonSerializer;

import java.io.IOException;
import java.io.InputStream;

/**
 * Socket 方式从输入流中读取字节并反序列化
 * */
@Slf4j
public class ObjectReader {

    private static final int MAGIC_NUMBER = 0x07060507;

    private ObjectReader() {}

    public static Object readObject(InputStream input) throws IOException {
        byte[] intBytes = new byte[4];
        input.read(intBytes);
        int magic = bytesToInt(intBytes);
        if (magic != MAGIC_NUMBER) {
            log.error("不识别的协议包 {}", magic);
            throw new RpcException(RpcError.UNKNOWN_PROTOCOL);
        }
        input.read(intBytes);
        int packageCode = bytesToInt(intBytes);
        Class<?> packageClass;
        if (packageCode == PackageType.REQUEST_PACK.getCode()) {
            packageClass = RpcRequest.class;
        } else if (packageCode == PackageType.RESPONSE_PACK.getCode()) {
            packageClass = RpcResponse.class;
        } else {
            log.error("不识别的数据包 {}", packageCode);
            throw new RpcException(RpcError.UNKNOWN_PACKAGE_TYPE);
        }
        input.read(intBytes);
        int serializerCode = bytesToInt(intBytes);
        CommonSerializer serializer = CommonSerializer.getByCode(serializerCode);
        if (serializer == null) {
            log.error("不识别的反序列化器 {}", serializerCode);
            throw new RpcException(RpcError.UNKNOWN_SERIALIZER);
        }
        input.read(intBytes);
        int length = bytesToInt(intBytes);
        byte[] bytes = new byte[length];
        input.read(bytes);
        return serializer.deserialize(bytes, packageClass);
    }

    /**
     * @param bytes byte[4]
     * */
    private static int bytesToInt(byte[] bytes) {
        int value;
        value = ((bytes[0] & 0xFF) << 24)
                | ((bytes[1] & 0xFF) << 16)
                | ((bytes[2] & 0xFF) << 8)
                | (bytes[3] & 0xFF);
        return value;
    }

}
